use std::fmt;
use std::ops::Add;

struct Wrapper(Vec<String>);
impl fmt::Display for Wrapper {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}]", self.0.join(","))
    }
}

fn main() {
    // let user = User {
    //     name: String::from("hboot"),
    //     age: 30,
    // };

    // println!("{:?}", Iterator::<String>::next(&user));
    // println!("{:?}", Iterator::<i32>::next(&user));

    let num = MyNum {};
    println!("{}", num.print(18));
    println!("{}", num.print(String::from("hboot")));

    // let animal: Animal = Animal;
    // <Animal as Dog>::speak();
    // <Animal as Bird>::speak();

    let dog = Collie;
    dog.speak();

    // let user = Wrapper(User {
    //     name: String::from("hboot"),
    // });

    let vec = vec![12, 23, 45];

    let wrapper = Wrapper(vec![String::from("hello"), String::from("hboot")]);
    println!("{}", wrapper);

    type My32 = i32;

    let age: My32 = 48;

    println!("{}", age + 48);

    let f: Thunk = Box::new(|| println!("hboot"));
    test(f);
    test_never();
}

type Thunk = Box<dyn Fn() + Send + 'static>;
//  let f:Thunk= Box::new(|| println!("hboot"));

fn test(f: Thunk) {
    f();
}

fn test_never() -> ! {
    panic!("err")
}

fn test_trait<T: ?Sized>(t: &T) {
    // ...
}
// pub trait Iterator {
//     type Item;

//     fn next(&self) -> Option<Self::Item>;
// }
pub trait Iterator<T> {
    fn next(&self) -> Option<T>;
}

// struct User {
//     name: String,
//     age: i32,
// }
// impl Iterator<String> for User {
//     fn next(&self) -> Option<String> {
//         Some(self.name.clone())
//     }
// }
// impl Iterator<i32> for User {
//     fn next(&self) -> Option<i32> {
//         Some(self.age)
//     }
// }

trait PrintNum<Rhs = i32> {
    fn print(&self, val: Rhs) -> Rhs;
}

struct MyNum {}

impl PrintNum for MyNum {
    fn print(&self, val: i32) -> i32 {
        val
    }
}
impl PrintNum<String> for MyNum {
    fn print(&self, val: String) -> String {
        val
    }
}

// trait Dog {
//     fn speak();
// }

// trait Bird {
//     fn speak();
// }

// struct Animal;

// impl Dog for Animal {
//     fn speak() {
//         println!("dog");
//     }
// }
// impl Bird for Animal {
//     fn speak() {
//         println!("bird");
//     }
// }

trait Animal {
    fn eat(&self) {
        println!("eat")
    }
}

trait Dog: Animal {
    fn speak(&self) {
        println!("speak");
        self.eat();
    }
}

struct Collie;

impl Dog for Collie {}

impl Animal for Collie {}

struct Millimeters(u32);
struct Meters(u32);

impl Add<Meters> for Millimeters {
    type Output = Millimeters;

    fn add(self, rhs: Meters) -> Self::Output {
        Millimeters(self.0 + (rhs.0 * 1000))
    }
}
